package tech

import "ssp/set"

func oneOrTwoGroupCloseCycle(head, tail GroupItem) bool {
	if head.cand == tail.cand {
		return isSameHouse(append(head.getCells(), tail.getCells()...))
	} else if head.group[1] == nil && tail.group[1] == nil {
		return head.group[0] == tail.group[0]
	}

	return false
}

func (g *Grid) aicgGetWeaks(node *ChainNode) []GroupItem {
	weaks := g.groupSeenGroups(node)
	if node.item.group[1] != nil {
		return weaks
	}
	if node.pre == nil || (node.pre != nil && node.pre.item.group != node.item.group) {
		for _, cand := range node.item.group[0].cands.GetList() {
			if cand == node.item.cand {
				continue
			}
			weak := GroupItem{cand, node.item.group}
			weaks = append(weaks, weak)
		}
	}
	return weaks
}

func (g *Grid) aicgGetStrongs(node *ChainNode) []GroupItem {
	strongs := g.groupedXCycleGetStrongs(node)
	if node.item.group[1] != nil {
		return strongs
	}
	if node.item.group[0].cands.Count() == 2 &&
		(node.pre == nil || (node.pre != nil && node.pre.item.group != node.item.group)) {
		for _, cand := range node.item.group[0].cands.GetList() {
			if cand == node.item.cand {
				continue
			}
			strong := GroupItem{cand, node.item.group}
			strongs = append(strongs, strong)
		}
	}
	return strongs
}

func (g *Grid) canRemoveAICGroup(items []GroupItem) (rmItems []GroupItem) {
	head := items[1]
	tail := items[len(items)-1]
	if head.cand == tail.cand {
		cells := append(head.getCells(), tail.getCells()...)
		if ok, rmCells := g.canRemoveSeenCands(set.NewSet(head.cand), cells); ok {
			for _, cell := range rmCells {
				rmItems = append(rmItems, GroupItem{head.cand, [9]*Cell{cell}})
			}
		}
	} else if head.group[0] == tail.group[0] && head.group[1] == nil && tail.group[1] == nil {
		for _, cand := range head.group[0].cands.GetList() {
			if cand == head.cand || cand == tail.cand {
				continue
			}
			rmItems = append(rmItems, GroupItem{cand, head.group})
		}
	} else {
		rmItems = append(rmItems, GroupItem{items[0].cand, items[0].group})
	}

	return
}

func (s *Solve) AICWithGroup3(g *Grid) (used bool, results []*Result) {
	c := Chain{
		g:            g,
		strategyName: "AIC With Group",
		getWeaks:     g.aicgGetWeaks,
		getStrongs:   g.aicgGetStrongs,
		closeCycle:   oneOrTwoGroupCloseCycle,
		canRemove:    g.canRemoveAICGroup,
	}

	return c.ExecStrategy3()
}
